/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.compomics.spectral.utilities.filtering.wavelet.daubechies;

import com.compomics.spectral.utilities.filtering.wavelet.daubechies.transformation.DaubechiesWaveletTransformer;
import com.compomics.spectral.utilities.filtering.wavelet.daubechies.tresholding.ThresholdGenerator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 *
 * @author Kenneth
 */
public class DaubechiesWaveletFilter {

    private double[] intensities;
    private final static DaubechiesWaveletTransformer daub = new DaubechiesWaveletTransformer();
    private double[] mz;
    private Map<Double, Double> sortingMap = new TreeMap<Double, Double>();
    private int framesize = 32;

    public DaubechiesWaveletFilter(double[] mz, double[] intensities) {
        this.intensities = intensities;
        this.mz = mz;
        if (mz.length > 2000) {
            framesize = (int) Math.sqrt(intensities.length / 3);
        } else {
            framesize = (int) Math.sqrt(intensities.length) / 3;
        }

        //Sort mz and intensities alike...
        for (int i = 0; i < mz.length; i++) {
            sortingMap.put(mz[i], intensities[i]);
        }
        //sorting 
        Object[] mzArray = sortingMap.keySet().toArray();
        Object[] intensityArray = sortingMap.values().toArray();
        for (int i = 0; i < mzArray.length; i++) {
            this.mz[i] = (double) mzArray[i];
            this.intensities[i] = (double) intensityArray[i];
        }
    }

    public double getTotalTreshold() {
        intensities = daub.daubTrans(intensities);
        double threshold = ThresholdGenerator.getThresHold(intensities);
        intensities = daub.invDaubTrans(intensities);
        return threshold;
    }

    public double[] filterTotalData() {
        List<Double> intensityList = new ArrayList<Double>();
        double threshold = getTotalTreshold();
        for (double anIntensity : intensities) {
            if (anIntensity > threshold) {
                intensityList.add(anIntensity);
            }
        }
        double[] target = new double[intensityList.size()];
        for (int i = 0; i < target.length; i++) {
            target[i] = intensityList.get(i);
        }
        return target;
    }

    public double[] transform() {
        double[] transformedIntensities = new double[intensities.length];
        System.arraycopy(intensities, 0, transformedIntensities, 0, intensities.length);
        double thresholdInDaubechies = ThresholdGenerator.getThresHold(daub.daubTrans(transformedIntensities));
        for (int i = 0; i < transformedIntensities.length; i++) {
            if (transformedIntensities[i] < thresholdInDaubechies) {
                transformedIntensities[i] = 0;
            }
        }
        daub.invDaubTrans(transformedIntensities);
        for (int i = 0; i < transformedIntensities.length; i++) {
            if (transformedIntensities[i] < 0) {
                transformedIntensities[i] = 0;
            }
        }
        return transformedIntensities;
    }

    public double[] filterFramedData(int framesize) {

        List<double[]> subArrays = splitArray(intensities, framesize);
        List<Double> intermediateList = new LinkedList<Double>();
        for (double[] aSubArray : subArrays) {

            double[] clonedArray = new double[aSubArray.length];
            System.arraycopy(aSubArray, 0, clonedArray, 0, aSubArray.length);
            clonedArray = daub.daubTrans(clonedArray);
            double threshold = ThresholdGenerator.getThresHold(clonedArray);

            for (int i = 0; i < aSubArray.length; i++) {
                if (aSubArray[i] < threshold) {
                    intermediateList.add(0.0);
                } else {
                    intermediateList.add(aSubArray[i]);
                }
            }

        }
        double[] returning = new double[intensities.length];
        Object[] returningArray = intermediateList.toArray();

        for (int i = 0; i < intensities.length; i++) {
            try {
                returning[i] = (double) returningArray[i];
            } catch (ArrayIndexOutOfBoundsException e) {
            }
        }
        return returning;
    }

    public static List<double[]> splitArray(double[] array, int max) {

        int x = array.length / max;

        int lower = 0;
        int upper = 0;

        List<double[]> list = new ArrayList<double[]>();

        for (int i = 0; i < x; i++) {

            upper += max;

            list.add(Arrays.copyOfRange(array, lower, upper));

            lower = upper;
        }

        if (upper < array.length - 1) {

            lower = upper;

            upper = array.length;

            list.add(Arrays.copyOfRange(array, lower, upper));
        }

        return list;
    }
}
